/**
 * 面试题 03.01. 三合一
 * https://leetcode-cn.com/problems/three-in-one-lcci/
 */
public class Solutions_mianshi_03_01 {
    public static void main(String[] args) {
//        TripleInOne obj = new TripleInOne(1);
//        obj.push(0, 1);
//        obj.push(0, 2);
//        int res1 = obj.pop(0);  // output: 1
//        System.out.println(res1);
//        int res2 = obj.pop(0);  // output: -1
//        System.out.println(res2);
//        int res3 = obj.pop(0);  // output: -1
//        System.out.println(res3);
//        boolean res4 = obj.isEmpty(0);  // output: true
//        System.out.println(res4);

        TripleInOne obj = new TripleInOne(2);
        obj.push(0, 1);
        obj.push(0, 2);
        obj.push(0, 3);
        int res1 = obj.pop(0);  // output: 2
        System.out.println(res1);
        int res2 = obj.pop(0);  // output: 1
        System.out.println(res2);
        int res3 = obj.pop(0);  // output: -1
        System.out.println(res3);
        int res4 = obj.peek(0);  // output: -1
        System.out.println(res4);
    }
}

/**
 * 一个数组来实现三个栈。
 * 传入一个stackSize参数，代表每个栈的大小。
 * 创建一个 stack 数组存储三个栈的元素，长度为 3 * stackSize
 * 其中用 index 数组表示三个栈在 stack 中进行存取元素的索引，长度为 3，默认值为 {0, 1, 2}
 * 即在 stack 中：
 * stack[0] = 0, 表示第 1 个栈存储了元素 0
 * stack[1] = 1, 表示第 2 个栈存储了元素 1
 * stack[2] = 2, 表示第 3 个栈存储了元素 2
 * stack[3] = 3, 表示第 1 个栈存储了元素 3
 * 栈中每存储一个元素，对应的栈的索引加 3
 * 每取出一个元素，对应的栈的索引减 3
 */
class TripleInOne {
    // 记录元素
    private int[] stack;
    // 记录索引：index[1] = 1，第 2 个栈现在要在索引 1 上存储元素
    private int[] index;

    public TripleInOne(int stackSize) {
        index = new int[]{0, 1, 2};
        // 每个栈的大小为 stackSize，那么三个栈的大小为 stackSize
        stack = new int[3 * stackSize];
    }

    public void push(int stackNum, int value) {
        int readIndex = index[stackNum];
        // 判断现在添加的索引位置，是否合法
        if (readIndex < stack.length) {
            // 将元素压入到 stackNum 的栈中
            stack[readIndex] = value;
            // 关键：索引需要向后移动 3 个索引，下一元素入栈的位置
            index[stackNum] += 3;
        }
    }

    public int pop(int stackNum) {
        // 判断 stackNum 栈是否为空
        if (isEmpty(stackNum)) {
            return -1;
        }
        // 一个元素出栈后，栈的索引减 3 个索引
        index[stackNum] -= 3;
        return stack[index[stackNum]];
    }

    public int peek(int stackNum) {
        // 判断 stackNum 栈是否为空
        if (isEmpty(stackNum)) {
            return -1;
        }
        // 为什么还要减 3？因为 index[stackNum] 记录的是存储下一元素的索引
        // 取值时，需要减 3，即取的是最后入栈的元素
        return stack[index[stackNum] - 3];
    }

    public boolean isEmpty(int stackNum) {
        // 原本的索引 0，1，2 未改变时，说明没有元素入栈
        return index[stackNum] < 3;
    }
}
